using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using KnowledgeQA.Data;
using KnowledgeQA.Models.Entities;
using KnowledgeQA.Models.DTOs;
using KnowledgeQA.Services.Interfaces;
using KnowledgeQA.Core.Interfaces;
using KnowledgeQA.Core.Utils;

namespace KnowledgeQA.Services.Implementations
{
    /// <summary>
    /// 文档服务实现类
    /// </summary>
    public class DocumentService : IDocumentService
    {
        private readonly KnowledgeQADbContext _context;
        private readonly ILogger<DocumentService> _logger;
        private readonly IAIService _aiService;
        private readonly IVectorService _vectorService;
        private readonly IServiceProvider _serviceProvider;

        public DocumentService(KnowledgeQADbContext context, ILogger<DocumentService> logger, IAIService aiService, IVectorService vectorService, IServiceProvider serviceProvider)
        {
            _context = context;
            _logger = logger;
            _aiService = aiService;
            _vectorService = vectorService;
            _serviceProvider = serviceProvider;
        }

        public async Task<PagedResponse<DocumentDTO>> GetDocumentsAsync(DocumentQueryRequest request)
        {
            try
            {
                var query = _context.Documents
                    .Include(d => d.Category)
                    .Where(d => !d.IsDeleted);

                // 应用过滤条件
                if (!string.IsNullOrEmpty(request.Keyword))
                {
                    var keyword = request.Keyword;
                    query = query.Where(d => d.Title.Contains(keyword) || (d.Description != null && d.Description.Contains(keyword)));
                }

                if (request.CategoryId.HasValue)
                {
                    query = query.Where(d => d.CategoryId == request.CategoryId);
                }

                if (!string.IsNullOrEmpty(request.FileType))
                {
                    query = query.Where(d => d.FileType == request.FileType);
                }

                if (!string.IsNullOrEmpty(request.Status))
                {
                    query = query.Where(d => d.Status == request.Status);
                }

                if (request.StartTime.HasValue)
                {
                    query = query.Where(d => d.CreatedAt >= request.StartTime);
                }

                if (request.EndTime.HasValue)
                {
                    query = query.Where(d => d.CreatedAt <= request.EndTime);
                }

                // 应用排序
                query = request.SortBy.ToLower() switch
                {
                    "title" => request.IsDescending ? query.OrderByDescending(d => d.Title) : query.OrderBy(d => d.Title),
                    "filesize" => request.IsDescending ? query.OrderByDescending(d => d.FileSize) : query.OrderBy(d => d.FileSize),
                    "createdat" => request.IsDescending ? query.OrderByDescending(d => d.CreatedAt) : query.OrderBy(d => d.CreatedAt),
                    _ => request.IsDescending ? query.OrderByDescending(d => d.CreatedAt) : query.OrderBy(d => d.CreatedAt)
                };

                // 获取总数
                var totalCount = await query.CountAsync();

                // 分页
                var documents = await query
                    .Skip((request.PageIndex - 1) * request.PageSize)
                    .Take(request.PageSize)
                    .ToListAsync();

                // 转换为DTO
                var documentDtos = documents.Select(MapToDTO).ToList();

                return PagedResponse<DocumentDTO>.Create(documentDtos, totalCount, request.PageIndex, request.PageSize);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文档列表失败");
                throw;
            }
        }

        public async Task<DocumentDTO?> GetDocumentByIdAsync(int id)
        {
            try
            {
                var document = await _context.Documents
                    .Include(d => d.Category)
                    .Include(d => d.DocumentChunks)
                    .FirstOrDefaultAsync(d => d.Id == id && !d.IsDeleted);

                return document != null ? MapToDTO(document) : null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文档失败，ID: {DocumentId}", id);
                throw;
            }
        }

        public async Task<DocumentDTO> CreateDocumentAsync(CreateDocumentRequest request)
        {
            try
            {
                var document = new Document
                {
                    Title = request.Title,
                    Description = request.Description,
                    CategoryId = request.CategoryId,
                    Tags = request.Tags != null ? System.Text.Json.JsonSerializer.Serialize(request.Tags) : null,
                    Status = "Pending"
                };

                _context.Documents.Add(document);
                await _context.SaveChangesAsync();

                _logger.LogInformation("文档创建成功，ID: {DocumentId}", document.Id);
                return MapToDTO(document);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建文档失败");
                throw;
            }
        }

        public async Task<DocumentDTO> UpdateDocumentAsync(int id, UpdateDocumentRequest request)
        {
            try
            {
                var document = await _context.Documents.FindAsync(id);
                if (document == null)
                {
                    throw new ArgumentException($"文档不存在，ID: {id}");
                }

                document.Title = request.Title;
                document.Description = request.Description;
                document.CategoryId = request.CategoryId;
                document.Tags = request.Tags != null ? System.Text.Json.JsonSerializer.Serialize(request.Tags) : null;
                document.UpdatedAt = DateTime.Now;

                await _context.SaveChangesAsync();

                _logger.LogInformation("文档更新成功，ID: {DocumentId}", id);
                return MapToDTO(document);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新文档失败，ID: {DocumentId}", id);
                throw;
            }
        }

        public async Task<bool> DeleteDocumentAsync(int id)
        {
            try
            {
                var document = await _context.Documents.FindAsync(id);
                if (document == null)
                {
                    return false;
                }

                document.IsDeleted = true;
                document.UpdatedAt = DateTime.Now;

                await _context.SaveChangesAsync();

                _logger.LogInformation("文档删除成功，ID: {DocumentId}", id);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除文档失败，ID: {DocumentId}", id);
                throw;
            }
        }

        public async Task<DocumentDTO> UploadDocumentAsync(IFormFile file, CreateDocumentRequest request)
        {
            try
            {
                // 验证文件
                if (file == null || file.Length == 0)
                {
                    throw new ArgumentException("文件不能为空");
                }

                // 检查文件大小（50MB限制）
                if (file.Length > 50 * 1024 * 1024)
                {
                    throw new ArgumentException("文件大小不能超过50MB");
                }

                // 生成文件名
                var fileName = $"{Guid.NewGuid()}_{file.FileName}";
                var uploadPath = Path.Combine("uploads", fileName);

                // 确保上传目录存在
                var uploadDir = Path.GetDirectoryName(uploadPath);
                if (!Directory.Exists(uploadDir))
                {
                    Directory.CreateDirectory(uploadDir!);
                }

                // 保存文件
                using (var stream = new FileStream(uploadPath, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                }

                // 创建文档记录
                var document = new Document
                {
                    Title = request.Title ?? file.FileName,
                    Description = request.Description,
                    FileName = fileName,
                    FilePath = uploadPath,
                    FileSize = file.Length,
                    FileType = file.ContentType,
                    CategoryId = request.CategoryId,
                    Tags = request.Tags != null ? System.Text.Json.JsonSerializer.Serialize(request.Tags) : null,
                    Status = "Pending"
                };

                _context.Documents.Add(document);
                await _context.SaveChangesAsync();

                _logger.LogInformation("文档上传成功，ID: {DocumentId}, 文件名: {FileName}", document.Id, file.FileName);
                return MapToDTO(document);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文档上传失败");
                throw;
            }
        }

        public async Task<List<DocumentDTO>> BatchUploadDocumentsAsync(IEnumerable<IFormFile> files, int? categoryId = null)
        {
            var results = new List<DocumentDTO>();

            foreach (var file in files)
            {
                try
                {
                    var request = new CreateDocumentRequest
                    {
                        Title = file.FileName,
                        CategoryId = categoryId
                    };

                    var result = await UploadDocumentAsync(file, request);
                    results.Add(result);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "批量上传文档失败，文件名: {FileName}", file.FileName);
                    // 继续处理其他文件
                }
            }

            return results;
        }

        public async Task<bool> ProcessDocumentAsync(int documentId)
        {
            try
            {
                var document = await _context.Documents.FindAsync(documentId);
                if (document == null)
                {
                    return false;
                }

                _logger.LogInformation("开始处理文档，ID: {DocumentId}, 文件: {FileName}", documentId, document.FileName);

                // 更新状态为处理中
                document.Status = "Processing";
                await _context.SaveChangesAsync();

                _logger.LogInformation($"开始获取文档处理器{document.FileType}");

                // 获取文档处理器
                var processor = GetDocumentProcessor(document.FileType);
                if (processor == null)
                {
                    document.Status = "Failed";
                    document.ErrorMessage = $"不支持的文件类型: {document.FileType}";
                    await _context.SaveChangesAsync();
                    return false;
                }

                // 构建完整的文件路径
                var filePath = document.FilePath;
                if (string.IsNullOrEmpty(filePath))
                {
                    document.Status = "Failed";
                    document.ErrorMessage = "文件路径为空";
                    await _context.SaveChangesAsync();
                    return false;
                }

                // 如果文件路径是相对路径，转换为绝对路径
                if (!Path.IsPathRooted(filePath))
                {
                    filePath = Path.Combine(Directory.GetCurrentDirectory(), filePath);
                }

                if (!File.Exists(filePath))
                {
                    document.Status = "Failed";
                    document.ErrorMessage = "文件不存在";
                    await _context.SaveChangesAsync();
                    return false;
                }

                // 处理文档
                var processResult = await processor.ProcessAsync(filePath, document);
                _logger.LogInformation($"文档处理器{document.FileType}处理完成");
                if (!processResult.Success)
                {
                    document.Status = "Failed";
                    document.ErrorMessage = processResult.ErrorMessage;
                    await _context.SaveChangesAsync();
                    return false;
                }

                // 保存文档块到数据库
                if (processResult.Chunks.Any())
                {
                    _context.DocumentChunks.AddRange(processResult.Chunks);
                    await _context.SaveChangesAsync();

                    // 生成向量嵌入并存储到向量数据库
                    await GenerateAndStoreVectorsAsync(processResult.Chunks, document);
                      _logger.LogInformation($"生成向量嵌入并存储到向量数据库完成");
                }
                else
                {
                     _logger.LogInformation($"文档处理器处理完成");
                }

                // 更新文档状态
                document.Status = "Completed";
                document.IsVectorized = true;
                document.ProcessingTime = processResult.ProcessingTime;
                document.ChunkCount = processResult.Chunks.Count;
                await _context.SaveChangesAsync();

                _logger.LogInformation("文档处理完成，ID: {DocumentId}, 块数: {ChunkCount}, 处理时间: {ProcessingTime}ms", 
                    documentId, processResult.Chunks.Count, processResult.ProcessingTime);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文档处理失败，ID: {DocumentId}", documentId);
                
                // 更新文档状态为失败
                var document = await _context.Documents.FindAsync(documentId);
                if (document != null)
                {
                    document.Status = "Failed";
                    document.ErrorMessage = ex.Message;
                    await _context.SaveChangesAsync();
                }
                
                return false;
            }
        }

        private IDocumentProcessor? GetDocumentProcessor(string fileType)
        {
            var processors = _serviceProvider.GetServices<IDocumentProcessor>();
            
            // 将MIME类型转换为文件扩展名
            var fileExtension = GetFileExtensionFromMimeType(fileType);
            
            _logger.LogInformation("查找文档处理器，原始类型: {FileType}, 转换后扩展名: {FileExtension}", fileType, fileExtension);
            
            var processor = processors.FirstOrDefault(p => p.CanProcess(fileExtension));
            
            if (processor != null)
            {
                _logger.LogInformation("找到文档处理器: {ProcessorType}", processor.GetType().Name);
            }
            else
            {
                _logger.LogWarning("未找到支持文件类型 {FileExtension} 的文档处理器", fileExtension);
            }
            
            return processor;
        }

        private string GetFileExtensionFromMimeType(string mimeType)
        {
            return mimeType.ToLower() switch
            {
                "application/pdf" => ".pdf",
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document" => ".docx",
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" => ".xlsx",
                "application/vnd.ms-excel" => ".xls",
                "application/msword" => ".doc",
                "text/plain" => ".txt",
                "text/markdown" => ".md",
                "text/csv" => ".csv",
                _ => mimeType.StartsWith("text/") ? ".txt" : mimeType
            };
        }

        private async Task GenerateAndStoreVectorsAsync(List<DocumentChunk> chunks, Document document)
        {
            try
            {
                _logger.LogInformation("开始生成向量嵌入，文档ID: {DocumentId}, 块数: {ChunkCount}", document.Id, chunks.Count);

                var vectors = new List<VectorData>();
                var validChunks = 0;
                var invalidChunks = 0;
                
                foreach (var chunk in chunks)
                {
                    try
                    {
                        _logger.LogInformation("向量内容1: {ChunkId},", chunk.Content);
           
                        // 使用EncodingUtils验证块内容
                        if (!EncodingUtils.IsValidTextContent(chunk.Content))
                        {
                            var invalidStats = EncodingUtils.GetTextContentStats(chunk.Content ?? "");
                            _logger.LogWarning("跳过无效的文档块，块ID: {ChunkId}, 内容长度: {ContentLength}, 无效比例: {InvalidRatio:F2}%", 
                                chunk.Id, chunk.Content?.Length ?? 0, invalidStats.InvalidRatio * 100);
                            invalidChunks++;
                            continue;
                        }
                        _logger.LogInformation("向量内容2: {ChunkId},", chunk.Content);
                        // 使用EncodingUtils清理块内容
                        var cleanedContent = EncodingUtils.CleanTextContent(chunk.Content ?? "");
                        
                        if (string.IsNullOrWhiteSpace(cleanedContent))
                        {
                            _logger.LogWarning("清理后的块内容为空，跳过块ID: {ChunkId}", chunk.Id);
                            invalidChunks++;
                            continue;
                        }
                        _logger.LogInformation("向量内容3: {ChunkId},", cleanedContent);
                        // 获取清理后的内容统计
                        var cleanedStats = EncodingUtils.GetTextContentStats(cleanedContent);
                        _logger.LogInformation("开始生成向量嵌入，块ID: {ChunkId}, 内容长度: {ContentLength}, 有效字符: {ValidChars}, 中文字符: {ChineseChars}, 预览: {Preview}", 
                            chunk.Id, cleanedContent.Length, cleanedStats.ValidCharCount, cleanedStats.ChineseCharCount,
                            cleanedContent.Length > 50 ? cleanedContent.Substring(0, 50) + "..." : cleanedContent);
                        _logger.LogInformation("向量内容4: {ChunkId},", cleanedContent);
                        // 生成向量嵌入
                        var embedding = await _aiService.GenerateEmbeddingAsync(cleanedContent);
                        _logger.LogInformation("向量内容5: {ChunkId},", chunk.Content);
                        if (embedding == null || embedding.Length == 0)
                        {
                            _logger.LogError("向量嵌入生成失败，块ID: {ChunkId}", chunk.Id);
                            invalidChunks++;
                            continue;
                        }
                        _logger.LogInformation("向量内容6: {ChunkId},", chunk.Content);
                        // 构建元数据
                        var metadata = new Dictionary<string, object>
                        {
                            ["documentId"] = document.Id,
                            ["documentTitle"] = document.Title,
                            ["chunkId"] = chunk.Id,
                            ["chunkIndex"] = chunk.ChunkIndex,
                            ["fileType"] = document.FileType,
                            ["categoryId"] = document.CategoryId ?? 0,
                            ["contentLength"] = cleanedContent.Length,
                            ["validCharCount"] = cleanedStats.ValidCharCount,
                            ["chineseCharCount"] = cleanedStats.ChineseCharCount,
                            ["invalidRatio"] = cleanedStats.InvalidRatio
                        };
                        _logger.LogInformation("向量内容7: {ChunkId},", chunk.Content);
                        // 添加标签信息
                        if (!string.IsNullOrEmpty(document.Tags))
                        {
                            var tags = document.Tags.Split(',', StringSplitOptions.RemoveEmptyEntries)
                                .Select(t => t.Trim())
                                .ToList();
                            metadata["tags"] = tags;
                        }

                        vectors.Add(new VectorData
                        {
                            VectorId = chunk.Id.ToString(),
                            Vector = embedding,
                            Metadata = metadata
                        });
                        _logger.LogInformation("向量内容8: {ChunkId},", chunk.Content);     
                        validChunks++;
                        _logger.LogInformation("向量生成完成，块ID: {ChunkId}, 向量维度: {VectorDimension}", chunk.Id, embedding.Length);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "生成向量失败，块ID: {ChunkId}", chunk.Id);
                        invalidChunks++;
                        // 继续处理其他块
                    }
                }
                _logger.LogInformation("向量内容9");
                _logger.LogInformation("向量生成统计，文档ID: {DocumentId}, 有效块: {ValidChunks}, 无效块: {InvalidChunks}", 
                    document.Id, validChunks, invalidChunks);

                // 批量存储向量
                if (vectors.Any())
                {
                    var success = await _vectorService.AddVectorsAsync(vectors);
                    if (success)
                    {
                        _logger.LogInformation("向量存储完成，文档ID: {DocumentId}, 向量数: {VectorCount}", document.Id, vectors.Count);
                    }
                    else
                    {
                        _logger.LogError("向量存储失败，文档ID: {DocumentId}", document.Id);
                    }
                }
                else
                {
                    _logger.LogWarning("没有有效的向量需要存储，文档ID: {DocumentId}", document.Id);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "生成和存储向量失败，文档ID: {DocumentId}", document.Id);
                throw;
            }
        }

        public async Task<bool> ReprocessDocumentAsync(int documentId)
        {
            try
            {
                var document = await _context.Documents.FindAsync(documentId);
                if (document == null)
                {
                    return false;
                }

                // 删除现有的文档块
                var existingChunks = await _context.DocumentChunks
                    .Where(c => c.DocumentId == documentId)
                    .ToListAsync();

                _context.DocumentChunks.RemoveRange(existingChunks);

                // 重新处理文档
                return await ProcessDocumentAsync(documentId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "重新处理文档失败，ID: {DocumentId}", documentId);
                return false;
            }
        }

        public async Task<DocumentStats> GetDocumentStatsAsync()
        {
            try
            {
                var stats = new DocumentStats();

                var documents = await _context.Documents
                    .Where(d => !d.IsDeleted)
                    .ToListAsync();

                stats.TotalDocuments = documents.Count;
                stats.ProcessedDocuments = documents.Count(d => d.Status == "Completed");
                stats.ProcessingDocuments = documents.Count(d => d.Status == "Processing");
                stats.FailedDocuments = documents.Count(d => d.Status == "Failed");
                stats.TotalFileSize = documents.Sum(d => d.FileSize);

                // 按类型统计
                stats.DocumentsByType = documents
                    .GroupBy(d => d.FileType)
                    .ToDictionary(g => g.Key, g => g.Count());

                // 按状态统计
                stats.DocumentsByStatus = documents
                    .GroupBy(d => d.Status)
                    .ToDictionary(g => g.Key, g => g.Count());

                return stats;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文档统计信息失败");
                throw;
            }
        }

        private DocumentDTO MapToDTO(Document document)
        {
            return new DocumentDTO
            {
                Id = document.Id,
                Title = document.Title,
                Description = document.Description,
                FileType = document.FileType,
                FileSize = document.FileSize,
                FileSizeFormatted = FormatFileSize(document.FileSize),
                CategoryId = document.CategoryId,
                CategoryName = document.Category?.Name,
                Tags = !string.IsNullOrEmpty(document.Tags) 
                    ? System.Text.Json.JsonSerializer.Deserialize<List<string>>(document.Tags) ?? new List<string>()
                    : new List<string>(),
                Status = document.Status,
                IsVectorized = document.IsVectorized,
                Version = document.Version,
                CreatedAt = document.CreatedAt,
                UpdatedAt = document.UpdatedAt,
                ChunkCount = document.DocumentChunks?.Count ?? 0
            };
        }

        private string FormatFileSize(long bytes)
        {
            string[] sizes = { "B", "KB", "MB", "GB" };
            double len = bytes;
            int order = 0;
            while (len >= 1024 && order < sizes.Length - 1)
            {
                order++;
                len = len / 1024;
            }
            return $"{len:0.##} {sizes[order]}";
        }
    }
} 